
#include "els_vm.h"
#include "els_vm_bytecode.h"
#include "els_vm_tree.h"
#include "hash.h"
#include "unit.h"
#include "inout.h"
#include "els.h"
#include "catch.h"

#define BUFFER_BLOCK 256
#define GARBAGE_BLOCK 1024
#define MIN_GARBAGE_BLOCK (GARBAGE_BLOCK/2)
#define MAXFILE 	20
char *els_file[];
int els_nfile;
Type_Tagged_String **els_constant = NULL;
Symbol *els_unit = NULL;
static Word els_nunit = 0;
static Long els_maxsymbol = 0;
static Word els_nconstant = 0;
static Long els_maxconstant = 0;
static void setglobal (void);
static void getglobal (void);

static void els_initsymbol (void){
    Word n;
    els_maxsymbol = BUFFER_BLOCK;
    els_unit = newvector(els_maxsymbol, Symbol);
}

void els_initconstant (void){
    els_maxconstant = BUFFER_BLOCK;
    els_constant = newvector(els_maxconstant, Type_Tagged_String *);
}

Word els_vm_findsymbol (Els_Type_Tree *t){
    if (els_unit == NULL) els_initsymbol(); 
    if (t->varindex == NOT_USED){
        if (els_nunit == els_maxsymbol){
            if (els_maxsymbol >= MAX_WORD) els_error("符号单元溢出");
            els_maxsymbol *= 2;
            if (els_maxsymbol >= MAX_WORD) els_maxsymbol = MAX_WORD; 
            els_unit = growvector(els_unit, els_maxsymbol, Symbol);
        }
        t->varindex = els_nunit;
        s_tag(els_nunit) = ELS_TYPE_NULL;
        els_nunit++;
    }
    return t->varindex;
}

Word els_vm_findsymbolbyname (char *name){
    return els_vm_findsymbol(els_lexgetstring(name));
}

Word els_vm_findconstant (Els_Type_Tree *t){
    if (els_constant == NULL) els_initconstant();
    if (t->constindex == NOT_USED){
        if (els_nconstant == els_maxconstant){
            if (els_maxconstant >= MAX_WORD) els_error("常量单元溢出");
            els_maxconstant *= 2;
            if (els_maxconstant >= MAX_WORD) els_maxconstant = MAX_WORD;
            els_constant = growvector(els_constant, els_maxconstant, Type_Tagged_String *);
        }
        t->constindex = els_nconstant;
        els_constant[els_nconstant] = &(t->ts);
        els_nconstant++;
    }
    return t->constindex;
}

Word  els_vm_findconstantbyname (char *name){
    return els_vm_findconstant(els_lexgetstring(name));
}

static char *els_travsymbol (int (*fn)(Object *)){
    Word i;
    for (i=0; i<els_nunit; i++) if (fn(&s_object(i))) return els_vm_nodebysymbol(i)->ts.str;
    return NULL;
}

int els_markobject (Object *o){
    if (tag(o) == ELS_TYPE_STRING && !tsvalue(o)->marked) tsvalue(o)->marked = 1;
    else if (tag(o) == ELS_TYPE_ARRAY) els_hashmark (avalue(o));
    else if ((o->tag == ELS_TYPE_FC || o->tag == ELS_TYPE_MARK) && !o->value.tf->marked) o->value.tf->marked = 1;
    return 0;
}

void els_pack (void){
    static Long block = GARBAGE_BLOCK;
    static Long nentity = 0;  
    Long recovered = 0;
    if (nentity++ < block) return;
    els_travstack(els_markobject); 
    els_travsymbol(els_markobject); 
    els_vm_travlock(els_markobject); 
    els_vm_travfallbacks(els_markobject); 
    recovered += els_strcollector();
    recovered += els_hashcollector();
    recovered += els_vm_funccollector();
    nentity = 0;			
    block=(16*block-7*recovered)/12;	
    if (block < MIN_GARBAGE_BLOCK) block = MIN_GARBAGE_BLOCK;
} 


/* 备用接口 0.4开始默认注释
static void setglobal (void){
    els_Typesystem_Object name = els_getstack(1);
    els_Typesystem_Object value = els_getstack(2);
    if (!els_isstr(name)) els_error("函数setglobal中有错误的参数");
    els_pushobject(value);
    els_storeglobal(els_getstr(name));
}

static void getglobal (void){
    els_Typesystem_Object name = els_getstack(1);
    if (!els_isstr(name)) els_error("函数getglobal中有错误的参数");
    els_pushobject(els_getglobal(els_getstr(name)));
}
*/

static Object *functofind;
static int checkfunc (Object *o){
    if (o->tag == ELS_TYPE_FC) return ((functofind->tag == ELS_TYPE_FC || functofind->tag == ELS_TYPE_MARK) && (functofind->value.tf == o->value.tf));
    if (o->tag == ELS_TYPE_CERRORPI) return ((functofind->tag == ELS_TYPE_CERRORPI || functofind->tag == ELS_TYPE_CMARK) && (functofind->value.f == o->value.f));
    return 0;
}


char *els_addfile (char *fn){
    if (els_nfile >= MAXFILE)
        return "too many files";
    if ((els_file[els_nfile++] = els_vm_strdup (fn)) == NULL)
        return "not enough memory";
    return NULL;
}
int els_delfile (void){
    els_vm_free(els_file[--els_nfile]); 
    return 1;
}